﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Xml;
using System.Reflection;
using SEAM.Core;
using SEAM.Exception.Formatter;
using SEAM.Exception.Publisher;

namespace SEAM.Exception
{
    public class ExceptionManager : IConfigurationSectionHandler
    {
        #region Member Variables

        private static ExceptionManager _manager;
        private string _applicationName;
        private PublisherMode _mode;
        private List<IExceptionPublisher> _publishers;

        #endregion

        #region Properties

        protected static ExceptionManager Manager
        {
            get { return _manager; }
        }
        public string ApplicationName
        {
            get { return _applicationName; }
            set { _applicationName = value; }
        }
        public PublisherMode Mode
        {
            get { return _mode; }
            set { _mode = value; }
        }
        protected List<IExceptionPublisher> Publishers
        {
            get { return _publishers; }
            set { _publishers = value; }
        }

        #endregion

        static ExceptionManager()
        {
            try
            {
                _manager = (ExceptionManager)ConfigurationManager.GetSection("SEAM/exception/exceptionManager");
            }
            catch { }
        }

        protected static int ComparePublisersByPriority(IExceptionPublisher x, IExceptionPublisher y)
        {
            if (x == null)
                return y == null ?  0 : -1;
            else 
            {
                if (y == null)
                    return 1;
                else
                    return x.Priority.CompareTo(y.Priority);
            }
        }
        public static bool PublishException(System.Exception ex)
        {
            return PublishException(ex, (IDictionary<string, object>) null);
        }

        public static bool PublishException(System.Exception ex, ICollection<object> additionalInfo)
        {
            IDictionary<string, object> dictInfo = new Dictionary<string, object>();
            foreach (object obj in additionalInfo)
            {
                if (obj != null)
                    dictInfo.Add(obj.GetType().FullName, obj);
            }
            return PublishException(ex, dictInfo);
        }

        public static bool PublishException(System.Exception ex, IDictionary<string, object> additionalInfo)
        {
            if (Manager == null || Manager.Mode == PublisherMode.None || ex == null)
                return false;
            else
            {
                bool retVal = false;
                foreach (IExceptionPublisher publisher in Manager.Publishers)
                {
                    if (publisher.Enabled)
                        retVal |= publisher.PublishException(ex, additionalInfo);

                    if (retVal && Manager.Mode == PublisherMode.Prefered)
                        break;
                }
                return retVal;
            }
        }

        #region IConfigurationSectionHandler Members

        public object Create(object parent, object configContext, XmlNode section)
        {
            if (section == null)
                return null;

            string applicationName = null;
            if (section.Attributes != null && section.Attributes["applicationName"] != null && section.Attributes["applicationName"].Value != null)
                applicationName = section.Attributes["applicationName"].Value;

            PublisherMode mode = PublisherMode.Prefered;
            if (section.Attributes != null && section.Attributes["mode"] != null && section.Attributes["mode"].Value != null)
                mode = (PublisherMode)Enum.Parse(typeof(PublisherMode), section.Attributes["mode"].Value);


            List<IExceptionPublisher> publishers = new List<IExceptionPublisher>();
            foreach (XmlNode child in section.ChildNodes)
            {
                IExceptionPublisher publisher = GetPublisher(child);
                if (publisher != null)
                    publishers.Add(publisher);
            }

            return new ExceptionManager()
            {
                ApplicationName = applicationName,
                Mode = mode,
                Publishers = publishers
            };
        }

        #endregion

        protected virtual IExceptionPublisher GetPublisher(XmlNode node)
        {
            if (node.Name != "publisher")
                return null;

            // Not going to absorb any exceptions here...might be an issue with the config.
            return (IExceptionPublisher)ObjectFactory.CreateObject(node.Attributes["type"].Value, node);
        }
    }
}
